! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
! Copyright (c) 2009, Roger Marchand, version 1.2
! All rights reserved.
!
! Redistribution and use in source and binary forms, with or without modification, are 
! permitted provided that the following conditions are met:
!
! 1. Redistributions of source code must retain the above copyright notice, this list of 
!    conditions and the following disclaimer.
!
! 2. Redistributions in binary form must reproduce the above copyright notice, this list
!    of conditions and the following disclaimer in the documentation and/or other 
!    materials provided with the distribution.
!
! 3. Neither the name of the copyright holder nor the names of its contributors may be 
!    used to endorse or promote products derived from this software without specific prior
!    written permission.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
! EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
! MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
! THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
! OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
!
! History
! May 2015 - D. Swales - Modified for COSPv2.0
! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
MODULE MOD_MISR_SIMULATOR
  use cosp_kinds,      only: wp
  use MOD_COSP_STATS,  ONLY: hist2D
  use mod_cosp_config, ONLY: R_UNDEF,numMISRHgtBins,numMISRTauBins,misr_histHgt,  &
                             misr_histTau
  implicit none 

  ! Parameters
  real(wp),parameter :: &
       misr_taumin = 0.3_wp,            & ! Minimum optical depth for joint-histogram
       tauchk      = -1.*log(0.9999999)   ! Lower limit on optical depth

contains

  ! ######################################################################################
  ! SUBROUTINE misr_subcolumn
  ! ######################################################################################
  SUBROUTINE MISR_SUBCOLUMN(npoints,ncol,nlev,dtau,zfull,at,sunlit,tauOUT,               &
                        dist_model_layertops,box_MISR_ztop)
    ! INPUTS
    INTEGER, intent(in) :: &
         npoints,    & ! Number of horizontal gridpoints
         ncol,       & ! Number of subcolumns
         nlev          ! Number of vertical layers
    INTEGER, intent(in),dimension(npoints) :: &
         sunlit        ! 1 for day points, 0 for night time
    REAL(WP),intent(in),dimension(npoints,ncol,nlev) :: &
         dtau          ! Optical thickness
    REAL(WP),intent(in),dimension(npoints,nlev) :: &
         zfull,      & ! Height of full model levels (i.e. midpoints), [nlev] is bottom
         at            ! Temperature (K)

    ! OUTPUTS
    REAL(WP),intent(out),dimension(npoints,ncol) :: &
         box_MISR_ztop,     & ! Cloud-top height in each column
         tauOUT               ! Optical depth in each column
    REAL(WP),intent(out),dimension(npoints,numMISRHgtBins) :: &
         dist_model_layertops ! 

    ! INTERNAL VARIABLES
    INTEGER :: ilev,j,loop,ibox,thres_crossed_MISR
    INTEGER :: iMISR_ztop
    REAL(WP) :: cloud_dtau,MISR_penetration_height,ztest

    ! ############################################################################
    ! Initialize
    box_MISR_ztop(1:npoints,1:ncol) = 0._wp  

    do j=1,npoints

       ! Only do retrieval over sunlit points
       if (sunlit(j) == 1) then

          ! Estimate distribution of Model layer tops
          dist_model_layertops(j,:)=0
          do ilev=1,nlev
             ! Define location of "layer top"
             if(ilev.eq.1 .or. ilev.eq.nlev) then
                ztest=zfull(j,ilev)
             else
                ztest=0.5_wp*(zfull(j,ilev)+zfull(j,ilev-1))
             endif

             ! Find MISR layer that contains this level
             ! *NOTE* the first MISR level is "no height" level
             iMISR_ztop=2
             do loop=2,numMISRHgtBins
                if ( ztest .gt. 1000*misr_histHgt(loop+1) ) then
                   iMISR_ztop=loop+1
                endif
             enddo
             
             dist_model_layertops(j,iMISR_ztop) = dist_model_layertops(j,iMISR_ztop)+1
          enddo

          ! For each GCM cell or horizontal model grid point   
          do ibox=1,ncol
             ! Compute optical depth as a cummulative distribution in the vertical (nlev).
             tauOUT(j,ibox)=sum(dtau(j,ibox,1:nlev))

             thres_crossed_MISR=0
             do ilev=1,nlev
                ! If there a cloud, start the counter and store this height
                if(thres_crossed_MISR .eq. 0 .and. dtau(j,ibox,ilev) .gt. 0.) then
                   ! First encountered a "cloud"
                   thres_crossed_MISR = 1  
                   cloud_dtau         = 0            
                endif

                if( thres_crossed_MISR .lt. 99 .and. thres_crossed_MISR .gt. 0 ) then
                   if( dtau(j,ibox,ilev) .eq. 0.) then
                      ! We have come to the end of the current cloud layer without yet 
                      ! selecting a CTH boundary. Restart cloud tau counter 
                      cloud_dtau=0
                   else
                      ! Add current optical depth to count for the current cloud layer
                      cloud_dtau=cloud_dtau+dtau(j,ibox,ilev)
                   endif
                   
                   ! If the cloud is continuous but optically thin (< 1) from above the 
                   ! current layer cloud top to the current level then MISR will like 
                   ! see a top below the top of the current layer.
                   if( dtau(j,ibox,ilev).gt.0 .and. (cloud_dtau-dtau(j,ibox,ilev)) .lt. 1) then
                      if(dtau(j,ibox,ilev) .lt. 1 .or. ilev.eq.1 .or. ilev.eq.nlev) then
                         ! MISR will likely penetrate to some point within this layer ... the middle
                         MISR_penetration_height=zfull(j,ilev)
                      else
                         ! Take the OD = 1.0 level into this layer
                         MISR_penetration_height=0.5_wp*(zfull(j,ilev)+zfull(j,ilev-1)) - &
                              0.5_wp*(zfull(j,ilev-1)-zfull(j,ilev+1))/dtau(j,ibox,ilev) 
                      endif
                      box_MISR_ztop(j,ibox)=MISR_penetration_height
                   endif
                   
                   ! Check for a distinctive water layer
                   if(dtau(j,ibox,ilev) .gt. 1 .and. at(j,ilev) .gt. 273 ) then
                      ! Must be a water cloud, take this as CTH level
                      thres_crossed_MISR=99
                   endif
                   
                   ! If the total column optical depth is "large" than MISR can't see
                   ! anything else. Set current point as CTH level
                   if(sum(dtau(j,ibox,1:ilev)) .gt. 5) then
                      thres_crossed_MISR=99           
                   endif
                endif
             enddo  
             
             ! Check to see if there was a cloud for which we didn't 
             ! set a MISR cloud top boundary
             if( thres_crossed_MISR .eq. 1) then
                ! If the cloud has a total optical depth of greater
                ! than ~ 0.5 MISR will still likely pick up this cloud
                ! with a height near the true cloud top
                ! otherwise there should be no CTH
                if(sum(dtau(j,ibox,1:nlev)) .gt. 0.5) then
                   ! keep MISR detected CTH
                elseif(sum(dtau(j,ibox,1:nlev)) .gt. 0.2) then
                   ! MISR may detect but wont likley have a good height
                   box_MISR_ztop(j,ibox)=-1
                else
                   ! MISR not likely to even detect.
                   ! so set as not cloudy
                   box_MISR_ztop(j,ibox)=0
                endif
             endif
          enddo  ! loop of subcolumns
       
       else
          ! Set night columns to fillvalue
          dist_model_layertops(j,:) = R_UNDEF
          box_MISR_ztop(j,:) = R_UNDEF
          tauOUT(j,:) = R_UNDEF
       endif  ! sunlit
    enddo  ! loop of gridpoints
    
    ! Modify MISR CTH for satellite spatial / pattern matcher effects
    ! Code in this region added by roj 5/2006 to account
    ! for spatial effect of the MISR pattern matcher.
    ! Basically, if a column is found between two neighbors
    ! at the same CTH, and that column has no hieght or
    ! a lower CTH, THEN misr will tend to but place the
    ! odd column at the same height as it neighbors.
    
    ! This setup assumes the columns represent a about a 1 to 4 km scale
    ! it will need to be modified significantly, otherwise
!	! DS2015: Add loop over gridpoints and index accordingly.
!    if(ncol.eq.1) then
!       ! Adjust based on neightboring points.
!       do j=2,npoints-1   
!          if(box_MISR_ztop(j-1,1) .gt. 0                             .and. &
!             box_MISR_ztop(j+1,1) .gt. 0                             .and. &
!             abs(box_MISR_ztop(j-1,1)-box_MISR_ztop(j+1,1)) .lt. 500 .and. &
!             box_MISR_ztop(j,1) .lt. box_MISR_ztop(j+1,1)) then
!             box_MISR_ztop(j,1) = box_MISR_ztop(j+1,1)    
!          endif
!       enddo
!    else
!       ! Adjust based on neighboring subcolumns.
!       do j=1,npoints
!          do ibox=2,ncol-1  
!                 if(box_MISR_ztop(j,ibox-1) .gt. 0                                .and. &
!                 box_MISR_ztop(j,ibox+1) .gt. 0                                .and. &
!                 abs(box_MISR_ztop(j,ibox-1)-box_MISR_ztop(j,ibox+1)) .lt. 500 .and. &
!                 box_MISR_ztop(j,ibox) .lt. box_MISR_ztop(j,ibox+1)) then
!                 box_MISR_ztop(j,ibox) = box_MISR_ztop(j,ibox+1)    
!               endif
!          enddo
!       enddo
!    endif
!    ! DS2015 END
     
  end SUBROUTINE MISR_SUBCOLUMN

  ! ######################################################################################
  ! SUBROUTINE misr_column
  ! ######################################################################################
  SUBROUTINE MISR_COLUMN(npoints,ncol,box_MISR_ztop,sunlit,tau,MISR_cldarea,MISR_mean_ztop,fq_MISR_TAU_v_CTH)

    ! INPUTS
    INTEGER, intent(in) :: &
         npoints,        & ! Number of horizontal gridpoints
         ncol              ! Number of subcolumns
    INTEGER, intent(in),dimension(npoints) :: &
         sunlit            ! 1 for day points, 0 for night time
    REAL(WP),intent(in),dimension(npoints,ncol) :: &
         box_MISR_ztop,  & ! Cloud-top height in each column
         tau               ! Column optical thickness

    ! OUTPUTS
    REAL(WP),intent(inout),dimension(npoints) :: &
         MISR_cldarea,   & ! Fraction area covered by clouds
         MISR_mean_ztop    ! Mean cloud top height MISR would observe
    REAL(WP),intent(inout),dimension(npoints,7,numMISRHgtBins) :: &
         fq_MISR_TAU_v_CTH ! Joint histogram of cloud-cover and tau

    ! INTERNAL VARIABLES
    INTEGER :: j
    LOGICAL,dimension(ncol) :: box_cloudy 
    real(wp),dimension(npoints,ncol) :: tauWRK,box_MISR_ztopWRK
    ! ############################################################################

    ! Compute column quantities and joint-histogram
    MISR_cldarea(1:npoints)                       = 0._wp
    MISR_mean_ztop(1:npoints)                     = 0._wp
    fq_MISR_TAU_v_CTH(1:npoints,1:7,1:numMISRHgtBins) = 0._wp
    tauWRK(1:npoints,1:ncol)                      = tau(1:npoints,1:ncol)
    box_MISR_ztopWRK(1:npoints,1:ncol)            = box_MISR_ztop(1:npoints,1:ncol)
    do j=1,npoints

       ! Subcolumns that are cloudy(true) and not(false)
       box_cloudy(1:ncol) = merge(.true.,.false.,tau(j,1:ncol) .gt. tauchk)

       ! Fill optically thin clouds with fill value
       where(.not. box_cloudy(1:ncol)) tauWRK(j,1:ncol)  = -999._wp
       where(box_MISR_ztopWRK(j,1:ncol) .eq. 0) box_MISR_ztopWRK(j,1:ncol)=-999._wp

       ! Compute joint histogram and column quantities for points that are sunlit and cloudy
       if (sunlit(j) .eq. 1) then 
          ! Joint histogram
          call hist2D(tauWRK(j,1:ncol),box_MISR_ztopWRK(j,1:ncol),ncol,misr_histTau,numMISRTauBins,&
               1000*misr_histHgt,numMISRHgtBins,fq_MISR_TAU_v_CTH(j,1:numMISRTauBins,1:numMISRHgtBins))
          fq_MISR_TAU_v_CTH(j,1:numMISRTauBins,1:numMISRHgtBins) =                       &
             100._wp*fq_MISR_TAU_v_CTH(j,1:numMISRTauBins,1:numMISRHgtBins)/ncol

          ! Column cloud area
          MISR_cldarea(j)=real(count(box_MISR_ztopWRK(j,1:ncol) .ne. -999.))/ncol

          ! Column cloud-top height
          if ( count(box_MISR_ztopWRK(j,1:ncol) .ne. -999.) .ne. 0 ) then
             MISR_mean_ztop(j) = sum(box_MISR_ztopWRK(j,1:ncol),box_MISR_ztopWRK(j,1:ncol) .ne. -999.)/ &
                  count(box_MISR_ztopWRK(j,1:ncol) .ne. -999.)
          else
             MISR_mean_ztop(j) = R_UNDEF
          endif

       else
          MISR_cldarea(j)          = R_UNDEF
          MISR_mean_ztop(j)        = R_UNDEF
          fq_MISR_TAU_v_CTH(j,:,:) = R_UNDEF
       endif
    enddo

  end SUBROUTINE MISR_COLUMN

end MODULE MOD_MISR_SIMULATOR
